package rmmk.datasources.parsing;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import rmmk.algorithms.preprocessing.preprocessors.RemoveEmptyDocuments;
import rmmk.framework.datasources.Document;

/**
 * Klasa do obsługi wczytywania dokumentów
 * @author Marcin
 *
 */
public class DocumentReader extends DefaultHandler {

	Logger logger = LoggerFactory.getLogger(DocumentReader.class);
	RemoveEmptyDocuments red = new RemoveEmptyDocuments();
	private StringBuffer tempText;
	private Vector<Document> documents = new Vector<>();
	private Document doc;
	boolean DATE, MKNOTE, UNKNOWN, TEXT, TOPICS, PLACES, PEOPLE, ORGS,
			EXCHANGES, TITLE, DATELINE;

	public void parseSingleDocument(String path) {
		DATE = false;
		MKNOTE = false;
		UNKNOWN = false;
		TEXT = false;
		TOPICS = false;
		PLACES = false;
		PEOPLE = false;
		ORGS = false;
		TITLE = false;
		DATELINE = false;
		EXCHANGES = false;
		tempText = new StringBuffer();
		doc = new Document();
		try {
			SAXParserFactory factory = SAXParserFactory.newInstance();
			factory.setValidating(false);
			factory.setFeature("http://xml.org/sax/features/validation", false);
			factory.setFeature(
					"http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
					false);
			factory.setFeature(
					"http://apache.org/xml/features/nonvalidating/load-external-dtd",
					false);

			SAXParser saxParser = factory.newSAXParser();

			DefaultHandler handler = this;

			// XMLFilter xmlFilter = new
			// XMLFilterEntityImpl(XMLReaderFactory.createXMLReader());
			// xmlFilter.setContentHandler(this);

			URI newPath = null;

			newPath = this.getClass().getResource(path).toURI();
			saxParser.parse(newPath.getPath(), handler);

		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Zwraca listę z wczytanymi wszystkimi dokumentami z 22 plików reuters'a
	 * @return wektor z dokumentami
	 */
	public List<Document> readDefautDocuments() {
		List<String> files = getDefaultFileList();
		
		return red.process(this.readDocuments(files));
	}
	
	public static ArrayList<String> getDefaultFileList()
	{
		ArrayList<String> files = new ArrayList<String>(22);

		for (int i = 0; i < 22; ++i)
			files.add(String.format("/reuters/reut2-%03d.sgm", i));
		
		return files;
	}

	/**
	 * Zwraca listę, zawierającą dokumenty wczytane z jednego z plików
	 * @param nr pliku do wczytania (0 do 21 )
	 * @return lista z dokumentami
	 */
	public List<Document> readOneDocument(int nr) {
		Vector<String> files = new Vector<String>();

		for (int i = nr; i < nr+1; ++i)
			files.add(String.format("/reuters/reut2-%03d.sgm", i));

		return red.process(this.readDocuments(files));
	}
	
	/**
	 * Zwraca listę zawierająca wczytany jedynie pierwszy z plików
	 * @return lista z dokumentami z pierwszego pliku
	 */
	public List<Document> readFirstDocument() {
		return this.readOneDocument(0);
	}

	/**
	 * Metoda zwraca listę odczytanych dokumentów
	 * @param files lista nazw plików w formacie /nazwa_pliku.rozszerzenie
	 * @return Wektor z dokumentami
	 */
	public Vector<Document> readDocuments(List<String> files) {

		for (String path : files)
			this.parseSingleDocument(path);

		logger.info("Łączna ilość wczytanych dokumentów: " + documents.size());
		
		return documents;
	}

	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if (qName.equalsIgnoreCase("REUTERS")) {

		}
		if (qName.equalsIgnoreCase("DATE")) {
			DATE = true;
		}
		if (qName.equalsIgnoreCase("MKNOTE")) {
			MKNOTE = true;
		}
		if (qName.equalsIgnoreCase("UNKNOWN")) {
			UNKNOWN = true;
		}
		if (qName.equalsIgnoreCase("BODY")) {
			TEXT = true;
		}
		if (qName.equalsIgnoreCase("TITLE")) {
			TITLE = true;
		}
		if (qName.equalsIgnoreCase("TOPICS")) {
			TOPICS = true;
		}
		if (qName.equalsIgnoreCase("PLACES")) {
			PLACES = true;
		}
		if (qName.equalsIgnoreCase("PEOPLE")) {
			PEOPLE = true;
		}
		if (qName.equalsIgnoreCase("DATELINE")) {
			DATELINE = true;
		}
		if (qName.equalsIgnoreCase("ORGS")) {
			ORGS = true;
		}
		if (qName.equalsIgnoreCase("EXCHANGES")) {
			EXCHANGES = true;
		}
	}

	public void characters(char ch[], int start, int length)
			throws SAXException {

		if (DATE) {
			this.doc.setDATE(new String(ch, start, length));
			DATE = false;
		}
		if (MKNOTE) {
			this.doc.setMKNOTE(new String(ch, start, length));
			MKNOTE = false;
		}
		if (UNKNOWN) {
			this.doc.setUNKNOWN(new String(ch, start, length));
			UNKNOWN = false;
		}
		if (TEXT) {
			this.tempText.append(new String(ch, start, length));
		}
		if (DATELINE) {
			this.doc.setDATELINE(new String(ch, start, length));
			DATELINE = false;
		}
		if (TITLE) {
			this.doc.setTITLE(new String(ch, start, length));
			TITLE = false;
		}
		if (TOPICS) {
			String s = new String(ch, start, length);
			this.doc.getTOPICS().add(s);
		}
		if (PLACES) {
			String s = new String(ch, start, length);
			this.doc.getPLACES().add(s);
		}
		if (PEOPLE) {
			String s = new String(ch, start, length);
			this.doc.getPEOPLE().add(s);
		}
		/*
		 * if (ORGS) { String s = new String(ch, start, length);
		 * this.doc.getORGS().add(s); } if (ORGS) { String s = new String(ch,
		 * start, length); this.doc.getORGS().add(s); }
		 */

	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if (qName.equalsIgnoreCase("REUTERS")) {
			documents.add(doc);
			doc = new Document();
		}
		if (qName.equalsIgnoreCase("PLACES")) {
			PLACES = false;
		}
		if (qName.equalsIgnoreCase("PEOPLE")) {
			PEOPLE = false;
		}
		if (qName.equalsIgnoreCase("ORGS")) {
			ORGS = false;
		}
		if (qName.equalsIgnoreCase("EXCHANGES")) {
			EXCHANGES = false;
		}
		if (qName.equalsIgnoreCase("TOPICS")) {
			TOPICS = false;
		}
		if (qName.equalsIgnoreCase("BODY")) {
			this.doc.setTEXT(this.tempText.toString());
			TEXT = false;
			this.tempText = new StringBuffer();
			
			if(this.doc.getTEXT() == null)
			{
				System.out.println("NULL TEXT DETECTED");
			}
		}
	}

}
